package org.abratuhi.kvngroupware.network;

import java.io.IOException;
import java.io.StringWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class Server implements Runnable{
	
	public final static Integer TIMEOUT = 1000;
	public final static Integer PAUSE = 100;
	
	/**/
	ServerSocket serverSocket;
	int port;
	boolean isUp = false;
	Thread thread;
	
	/**/
	HashMap<String, Client> clients = new HashMap<String, Client>();
	
	/**/
	//public KVNGroupwareServer kvnserver;
	MessageProceeder mproceeder;
	
	
	/**/
	public Server(MessageProceeder mproceeder, int port){
		this.mproceeder = mproceeder;
		this.port = port;
	}
	
	public synchronized Client getClient(String id){
		return this.clients.get(id);
	}
	
	public synchronized String[] getClientIds(){
		return clients.keySet().toArray(new String[clients.size()]);
	}
	
	synchronized void register(Client client){
		this.clients.put(client.getId(), client);
	}
	
	synchronized void unregister(Client client){
		this.clients.remove(client.getId());
	}

	/**/
	public synchronized void up(){
		if(getIsUp() == true) return;
		try {
			if(serverSocket==null) serverSocket = new ServerSocket(port);
			setIsUp(true);
			
			System.out.println("Server:\t UP, port="+port+".");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void down(){
		//try {
			//serverSocket.close();
			System.out.println("Server:\t DOWN, port="+port+".");
		//} catch (IOException e) {
		//	e.printStackTrace();
		//}
	}
	
	/**/
	public void run(){
		System.out.println("SERVER [start]");
		while(getIsUp()){
			try {
				/* wait for new connections*/
				Socket s;
				if(serverSocket != null && !serverSocket.isClosed()){
					s = serverSocket.accept();
					S_Client tclient = new S_Client(s, mproceeder, this);
					tclient.start();
					System.out.println("SERVER [new s_client]");
				}
				Thread.sleep(PAUSE);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				System.out.println("SERVER [interrupt]");
				//setRunOK(false);
				break;
			}
		}
		System.out.println("SERVER [stop]");
	}
	
	public void start(){
		this.setIsUp(true);
		this.thread = new Thread(this);
		this.thread.start();
	}
	
	public void stop(){
		/* stop clients*/
		for(int i=0; i<clients.size(); i++){
			clients.get(i).stop();
		}
		
		/* unset run flag */
		setIsUp(false);
		
		/* interrupt run routine*/
		thread.interrupt();
	}
	
	public void cleanup(){
		String[] keys = clients.keySet().toArray(new String[clients.size()]);
		for(int i=0; i<keys.length; i++)
			if(clients.get(keys[i]).getSocket().isClosed()) clients.remove(keys[i]);
	}
	
	public synchronized boolean getIsUp(){
		return this.isUp;
	}
	
	public synchronized void setIsUp(boolean run){
		this.isUp = run;
	}
	
	public synchronized void switchIsUp(){
		this.isUp = (this.isUp == true)? false:true;
	}
	
	public String getSummary(){
		StringWriter sw = new StringWriter();
		sw.append("**************************************************"+"\n");
		sw.append("*************** SERVER STATISTICS: ***************"+"\n");
		sw.append("**************************************************"+"\n");
		sw.append("Server on port:\t"+port+"\n");
		sw.append("Server is up:\t"+String.valueOf(getIsUp())+"\n");
		sw.append("Server's # of clients:\t"+clients.size()+"\n");
		
		return sw.toString();
	}

}
